package hu.bme.aut.consulttime.server.entityservices;

import hu.bme.aut.consulttime.client.TeamService;
import hu.bme.aut.consulttime.entitydtos.TeamDTO;
import hu.bme.aut.consulttime.entitydtos.UserDTO;
import hu.bme.aut.consulttime.server.entities.Project;
import hu.bme.aut.consulttime.server.entities.Semester;
import hu.bme.aut.consulttime.server.entities.Student;
import hu.bme.aut.consulttime.server.entities.StudentTeamMembership;
import hu.bme.aut.consulttime.server.entities.Team;
import hu.bme.aut.consulttime.server.entities.User;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class TeamServiceImpl extends RemoteServiceServlet implements
		TeamService {
	
	private static final long serialVersionUID = 6601131056047066070L;

	public static final EntityManager entityManager() {
		return EntityManagerFactoryWrapper.get().createEntityManager();
	}

	@Override
	public Boolean createTeam(TeamDTO teamDTO) {

		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();

		Team team = new Team();
		team.setTeamId(teamDTO.getTeamId());
		team.setName(teamDTO.getName());

		try {
			tx.begin();
			team.setProject(em.find(Project.class, teamDTO.getProjectId()));
			team.setSemester(em.find(Semester.class, teamDTO.getSemesterId()));
			em.persist(team);
			tx.commit();
			return true;
		} catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	@Override
	public TeamDTO retrieveTeam(long teamId) {

		EntityManager em = entityManager();
		Team team = null;

		try {
			team = em.find(Team.class, teamId);
		} catch (Throwable t) {
			t.printStackTrace();
		} finally {
			if (em != null) {
				em.close();
			}
		}

		if (team != null) {
			TeamDTO teamDTO = new TeamDTO(team.getTeamId(), team.getName(), team
					.getProject().getProjectId(), team.getSemester()
					.getSemesterId());
		
			/*List<UserDTO> userDTOs = new ArrayList<UserDTO>();
						
			for(StudentTeamMembership stm : team.getStudentMemberships()){
		
				UserDTO student = new UserDTO();
				student.setUserId(stm.getStudent().getUserId());
				student.setUserName(stm.getStudent().getUserName());
				student.setEmail(stm.getStudent().getEmail());
				student.setEmailNotification(stm.getStudent().isEmailNotification());
				student.setFirstName(stm.getStudent().getFirstName());
				student.setLastName(stm.getStudent().getLastName());
				userDTOs.add(student);
			}
			
			teamDTO.setMembers(userDTOs);*/
			return teamDTO;
		} else {
			return null;
		}
	}

	@Override
	public Boolean deleteTeam(long teamId) {

		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();

		try {
			tx.begin();
			em.remove(em.find(Team.class, teamId));
			tx.commit();

			return true;
		} catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} finally {
			if (em != null) {
				em.close();
			}
		}
	}

	@Override
	public List<String> retrieveSemesters() {
		EntityManager em = entityManager();
		List<Semester> semesters = null;

		try {
			TypedQuery<Semester> query = em.createQuery(
					"select s from Semester s", Semester.class);
			semesters = query.getResultList();
		} finally {
			em.close();
		}

		// Convert to String
		List<String> semesteList = new ArrayList<String>();
		for (Semester tmp : semesters) {
			semesteList.add(tmp.getSemesterId());
		}
		return semesteList;
	}

	@Override
	public List<TeamDTO> retrieveTeams() {
		EntityManager em = entityManager();
		List<Team> teams = null;

		try {
			TypedQuery<Team> query = em.createQuery(
					"select s from Team s", Team.class);
			teams = query.getResultList();
		} finally {
			em.close();
		}

		List<TeamDTO> teamDTOs = new ArrayList<TeamDTO>();
		for (Team tmp : teams) {
			TeamDTO team = new TeamDTO();
			team.setProjectId(tmp.getProject().getProjectId());
			team.setName(tmp.getName());
			team.setTeamId(tmp.getTeamId());
			team.setSemesterId(tmp.getSemester().getSemesterId());
			
		// Add Members
			team.setMembers(retrieveMembers(tmp.getTeamId()));
			//team.setMembers(new ArrayList<UserDTO>());
			
			teamDTOs.add(team);
		}

		return teamDTOs;
	}
	
	@Override
	public List<TeamDTO> retrieveTeams(long projectId) {
		EntityManager em = entityManager();
		List<Team> teams = null;

		try {
			TypedQuery<Team> query = em.createQuery(
					"select t from Team t where t.project.projectId = ?1", Team.class);
			query.setParameter(1, projectId);
			teams = query.getResultList();
		} finally {
			em.close();
		}

		List<TeamDTO> teamDTOs = new ArrayList<TeamDTO>();
		for (Team tmp : teams) {
			TeamDTO team = new TeamDTO();
			team.setProjectId(tmp.getProject().getProjectId());
			team.setName(tmp.getName());
			team.setTeamId(tmp.getTeamId());
			team.setSemesterId(tmp.getSemester().getSemesterId());
			teamDTOs.add(team);
		}

		return teamDTOs;
	}
	
	@Override
	public List<UserDTO> retrieveMembers(long teamId) {
		EntityManager em = entityManager();
		List<Student> students = null; 

		try {
			TypedQuery<Student> query = em.createQuery("select s from Student s join s.teamMemberships tm where tm.studentTeamMembershipId.team.teamId = ?1", Student.class);
			query.setParameter(1, teamId);
			students = query.getResultList();
		} 
		finally {
			em.close();
		}

		List<UserDTO> studentDTOs = new ArrayList<UserDTO>(students != null ? students.size() : 0);
	    if (students != null) {
	      for (User user : students) {
	        studentDTOs.add(new UserDTO(user.getUserId(), user.getUserName(), user.getFirstName(), user.getLastName(), user.getEmail(), user.isEmailNotification()));
	      }
	    }
		
		return studentDTOs;
	}

	@Override
	public List<UserDTO> retrieveAvailableStudents(String semesterId) {
		EntityManager em = entityManager();
		List<Student> students = null;
		

		//Get students
		try {
			TypedQuery<Student> query = em.createQuery("select s from Student s", Student.class);
			students = query.getResultList();
		} catch (Exception e) {
			e.printStackTrace();
		}

		List<UserDTO> userDTOs = new ArrayList<UserDTO>();
		boolean studentOk;
		for(Student tmpStudent : students){
			studentOk = true;

			//If the student not in team in the semester
			for(StudentTeamMembership tmpMembership : tmpStudent.getTeamMemberships()){
				if(tmpMembership.getTeam().getSemester().getSemesterId().equals(semesterId)){
					studentOk = false;
				}
			}
			
			if(studentOk){
				UserDTO tutor = new UserDTO();
				tutor.setUserId(tmpStudent.getUserId());
				tutor.setUserName(tmpStudent.getUserName());
				tutor.setEmail(tmpStudent.getEmail());
				tutor.setEmailNotification(tmpStudent.isEmailNotification());
				tutor.setFirstName(tmpStudent.getFirstName());
				tutor.setLastName(tmpStudent.getLastName());
				userDTOs.add(tutor);
			}
		}

		return userDTOs;
	}

	@Override
	public Boolean updateTeamInfos(TeamDTO teamDTO) {
		EntityManager em = entityManager();
		try {			
			Team team = em.find(Team.class, teamDTO.getTeamId());
			if (team != null) {
				em.getTransaction().begin();

				team.setName(teamDTO.getName());
				team.setProject(em.find(Project.class, teamDTO.getProjectId()));
				team.setSemester(em.find(Semester.class, teamDTO.getSemesterId()));
				
				em.merge(team);
				em.getTransaction().commit();
			}
			else{
				return false;
			}

		} finally {
			em.close();
		}
		return true;
	}
	
	@Override
	public Boolean updateTeamMembers(TeamDTO teamDTO) {
		EntityManager em = entityManager();
		try {			
			Team team = em.find(Team.class, teamDTO.getTeamId());
			if (team != null) {
				em.getTransaction().begin();	
				
				//Delete old memberships
				Query deleteQuery = em.createQuery("Delete from StudentTeamMembership stm where stm.studentTeamMembershipId.team = ?1");
				deleteQuery.setParameter(1, team).executeUpdate();
				
				//Add new memberships
				List<StudentTeamMembership> stmList = new ArrayList<StudentTeamMembership>();
				if(!teamDTO.getMembers().isEmpty()){
					//refresh STM-s
					for(UserDTO tmp : teamDTO.getMembers()){
						
						TypedQuery<Student> query = em.createQuery("select s from Student s where s.userName = ?1", Student.class);
						query.setParameter(1, tmp.getUserName());
						Student student = query.getSingleResult();
						
						StudentTeamMembership newSTM = new StudentTeamMembership(
								student,
								em.find(Team.class, teamDTO.getTeamId())
								);
						stmList.add(newSTM);
						
						em.persist(newSTM);
					}
				}
				team.setStudentMemberships(stmList);
				em.merge(team);

				em.getTransaction().commit();
			}
			else{
				return false;
			}

		} finally {
			em.close();
		}
		return true;
	}
	
}
